home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 526-550 / disk_539 / pf / source / pf1.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  17KB  |  615 lines

  1. /*----------------------------------------------------------------------*
  2.  | File: PF.c (short for PRINTFILES.c) - V1.15 - MLO 910609             |
  3.  +----------------------------------------------------------------------+
  4.  | This file is an utility for the HP DeskJet 500 printer on the Amiga; |
  5.  | has been written for the SAS C-Compiler v5.10,  and structured to be |
  6.  | easily modified for different computers (e.g. IBM PC's). Its purpose |
  7.  | is to send the correct escape sequence  to direct the printer to use |
  8.  | an internal font,  then to print  one or more files;  the printer is |
  9.  | reset to the default,  UNLESS no file names are given:  in this case |
  10.  | the printer is  left initialised as it was.  I have foreseen  also a |
  11.  | special printing mode: 2 pages (55 lines and 80 columns each) on the |
  12.  | same sheet,  in landscape mode  with a small font and a nice border. |
  13.  +----------------------------------------------------------------------+
  14.  | Usage: PF [switches] [file [file [file ... ] ] ] ; from CLI only.    |
  15.  | Switches:    -l : landscape (default is portrait);                   |
  16.  |              -i : italic (default is roman);                         |
  17.  |             -bN : insert N blanks at the beginning of every line;    |
  18.  |             -aN : tAb stops every N characters (default: 8);         |
  19.  |              -g : Letter-Gothic font (default is Courier);           |
  20.  |              -t : Times font (default is Courier);                   |
  21.  |              -s : small pitch (Courier: 16.67 cpi; Let.Got.: 24cpi); |
  22.  |              -x : extra-small pitch (20 cpi - for Courier only);     |
  23.  |              -8 : 8 lpi (default is 6 lpi);                          |
  24.  |              -6 : 6 points high fonts (default is 12 points fonts);  |
  25.  |              -d : draft quality (default is letter quality);         |
  26.  |              -2 : special mode (2 pages every side).                 |
  27.  | The s/x/l switches are ignored when incompatible with selected font; |
  28.  | the "normal" pitch  is 10 cpi for Courier,  and 12 for Letter-Gothic |
  29.  | (Times is a proportional font). The switches can be specified eg. as |
  30.  | -g -8 -s or as -g8s (for Letter-Gothic font, 8 lpi and 24 cpi); only |
  31.  | the -bN/-aN switches must be alone,  or the last ones in a sequence. |
  32.  | All switches different from -d/-a will be ignored if -2 is selected. |
  33.  | All non-printable characters (00 to 037 and 0137) are deleted.       |
  34.  +----------------------------------------------------------------------+
  35.  | Giving PF with invalid switches (or PF without any argument) a short |
  36.  | help screen will be printed on stdout.                               |
  37.  +---------------------------------------------------------+------------*
  38.  | Author:  Maurizio Loreti, aka MLO or I3NOO.             |
  39.  | Address: University of Padova - Department of Physics   |
  40.  |          Via F. Marzolo, 8 - 35131 PADOVA - Italy       |
  41.  | Phone:   (39)(49) 844-313         FAX: (39)(49) 844-245 |
  42.  | E-Mail:  LORETI at IPDINFN (BITNET); or VAXFPD::LORETI  |
  43.  |         (DECnet) - VAXFPD is node 38.257 i.e. 39169; or |
  44.  |          LORETI@PADOVA.INFN.IT (INTERNET).              |
  45.  | Home: Via G. Donizetti 6 - 35010 CADONEGHE (PD) - Italy |
  46.  *---------------------------------------------------------*/
  47.  
  48. #include "pf1.h"
  49.  
  50. /**
  51.  | ANSI prototypes
  52. **/
  53.  
  54. void    CheckDefaults(void);
  55. void    Cleanup(int code);
  56. void    ClearPageBuffer(void);
  57. void    ClearThisPage(void);
  58. void    Detab(char *buffer, int length);
  59. void    DoubleLine(char *left, char *right);
  60. void    EjectPage(void);
  61. void    ExitProgram(void);
  62. void    FlushBuffers(void);
  63. void    Header(int type);
  64. void    InitPrinter(void);
  65. void    InterLine(void);
  66. void    OutLine(void);
  67. void    ResetPrinter(void);
  68. char  **Setup(int *pArgc, char **argv);
  69. void    Syntax(void);
  70.  
  71. /**
  72.  | Main program: the approach is strictly top-down, and
  73.  | the meaning should be clear also without comments.
  74. **/
  75.  
  76. main(
  77.   int argc,
  78.   char **argv
  79. ){
  80.   int bufferLength = LINE_LENGTH;
  81.  
  82.   argv = Setup(&argc, argv);
  83.   InitPrinter();
  84.   bufferLength -= nBlanks;
  85.  
  86.   for (; argc--; argv++) {
  87.     if ((fp = fopen(*argv, "r")) == NULL) {
  88.       printf("Can't open input file %s ...\n", *argv);
  89.       continue;
  90.     }
  91.     printf("Printing file %s ... ", *argv);
  92.     while (fgets(Buffer, bufferLength, fp) != NULL) {
  93.       Detab(Buffer, bufferLength);
  94.       OutLine();
  95.     }
  96.     printf("done.\n");
  97.     fclose(fp);
  98.     fp = NULL;
  99.     ClearThisPage();
  100.   }
  101.   FlushBuffers();
  102.   ExitProgram();
  103. }
  104.  
  105. void CheckDefaults(void)
  106. {
  107.  
  108. /**
  109.  | As the name says, this procedure checks for incompatible options
  110.  | selected: e.g. the only Landscape fonts are Courier, so to give
  111.  | the command PF -TL ... is an error. I suppose that the internal
  112.  | fonts only are present; otherwise this procedure should be modified.
  113.  | Checks:
  114.  | -> Letter-Gothic: 12 or 24 cpi; portrait only.
  115.  | -> Times: proportional; portrait only.
  116.  | -> Courier: 10 or 20 cpi; plus 16.67 cpi for Courier Roman (not
  117.  |    allowed for Courier Italic).
  118.  | -> Landscape/Italic not allowed.
  119.  | -> The number of extra spaces inserted before every line must be
  120.  |    not negative.
  121. **/
  122.  
  123.   switch (Font) {
  124.     case GOTHIC:
  125.       Orientation = PORTRAIT;
  126.       if (Pitch == P10CPI) {
  127.         Pitch = P12CPI;
  128.       } else {
  129.         Pitch = P24CPI;
  130.       }
  131.       break;
  132.     case TIMES:
  133.       Orientation = PORTRAIT;
  134.       Pitch = PROPORTIONAL;
  135.       break;
  136.     case COURIER:
  137.       if (Pitch == P16_67CPI   &&   Style == ITALIC) {
  138.         Pitch = P20CPI;
  139.       }
  140.       break;
  141.   }
  142.  
  143.   if (Orientation == LANDSCAPE) {
  144.     Style = ROMAN;
  145.   }
  146.  
  147.   if (nBlanks < 0) {
  148.     nBlanks = 0;
  149.   } else {
  150.     if (nBlanks) {
  151.       Buffer = inBuffer + nBlanks;
  152.       memset(inBuffer, BLANK, nBlanks);
  153.     }
  154.   }
  155. }
  156.  
  157. void Cleanup(
  158.   int code
  159. ){
  160.  
  161. /**
  162.  | Releases all system resources (closes opened files
  163.  | and frees heap memory - if any). "code" is the
  164.  | status to be returned to the operating system.
  165. **/
  166.  
  167.   if (fp  != NULL)                fclose(fp);
  168.   if (prt != NULL)                fclose(prt);
  169.   if (pPB != NULL) {
  170.     if (pPB->line[0] != NULL)     free(pPB->line[0]);
  171.     free(pPB);
  172.   }
  173.   exit(code);
  174. }
  175.  
  176. void ClearPageBuffer(void)
  177. {
  178.  
  179. /**
  180.  | This routine resets the content of the page buffer
  181.  | used in the 2-pages-on-a-sheet mode to all-blank
  182.  | lines, and the pointer to the next line to be filled
  183.  | to the first line in the buffer.
  184. **/
  185.  
  186.   memset(pPB->line[0], BLANK, BUFFER_SIZE);
  187.   ThisLine = 0;
  188. }
  189.  
  190. void ClearThisPage(void)
  191. {
  192.  
  193. /**
  194.  | Called every end of file: in the normal mode, ejects a page;
  195.  | in the 2-pages mode, switches from the left to the right page
  196.  | (if there is at least a line on this page), and leaving the
  197.  | remainder of the lines on the current page all blank.
  198. **/
  199.  
  200.   switch (PageMode) {
  201.     case SINGLE_PAGE:
  202.       EjectPage();
  203.       break;
  204.     case LEFT_PAGE:
  205.       if (ThisLine) {
  206.         Header(UP);
  207.         PageMode = RIGHT_PAGE;
  208.         ThisLine = 0;
  209.       }
  210.       break;
  211.     case RIGHT_PAGE:
  212.       if (ThisLine) {
  213.         FlushBuffers();
  214.         PageMode = LEFT_PAGE;
  215.         ClearPageBuffer();
  216.       }
  217.       break;
  218.   }
  219. }
  220.  
  221. void Detab(
  222.   char *buffer,
  223.   int length
  224. ){
  225.  
  226. /**
  227.  | Translates TAB stops to blanks: TAB stops are assumed at columns
  228.  | (1 + N * nTabs), with N = 1, 2, ... ; the default value of nTabs
  229.  | is 8, and can be changed using the command switches. In the same
  230.  | time non-printable characters are deleted from the input string:
  231.  | for non-printable I mean characters from 00 to 037 and 0177, assuming
  232.  | that characters over 0177 have special meaning different for every
  233.  | computer and that nothing can be said about them.
  234.  | The buffer can hold "length" characters only.
  235. **/
  236.  
  237.   char temp[LINE_LENGTH];                 /* Internal buffer */
  238.   char *pC1, *pC2;                        /* Temporary pointers */
  239.   char *pEnd;                             /* Pointer to the buffer end */
  240.  
  241.   strcpy(temp, buffer);
  242.   pEnd = (buffer + length - 1);
  243.   for (pC1 = temp, pC2 = buffer; *pC1 && pC2 < pEnd; pC1++) {
  244.     if (*pC1 == TAB) {
  245.       do {
  246.         *pC2++ = BLANK;
  247.       } while (((pC2 - buffer) % nTabs) && (pC2 < pEnd));
  248.     } else {
  249.       if (isspace(*pC1)  ||  !iscntrl(*pC1)) {
  250.         *pC2++ = *pC1;
  251.       }
  252.     }
  253.   }
  254.   *pC2 = NIHIL;
  255. }
  256.  
  257. void DoubleLine(
  258.   char *left,
  259.   char *right
  260. ){
  261.  
  262. /**
  263.  | Prints a line in the 2-pages mode, the two parameters being
  264.  | pointers to the left-page line and the right-page line; a
  265.  | blank line is printed if the corresponding pointer is NULL.
  266. **/
  267.  
  268.   if (left == NULL) {
  269.     fprintf(prt, "%c%*c%c%*c",
  270.         V_LINE, TOTAL_LENGTH, BLANK, V_LINE, SEP_LENGTH, BLANK);
  271.   } else {
  272.     fprintf(prt, "%c%*c%.*s%*c%c%*c",
  273.         V_LINE, SIDE_LENGTH, BLANK, OUTPUT_LENGTH, left,
  274.         SIDE_LENGTH, BLANK, V_LINE, SEP_LENGTH, BLANK);
  275.   }
  276.  
  277.   if (right == NULL) {
  278.     fprintf(prt, "%c%*c%c\r",
  279.         V_LINE, TOTAL_LENGTH, BLANK, V_LINE);
  280.   } else {
  281.     fprintf(prt, "%c%*c%.*s%*c%c\r",
  282.         V_LINE, SIDE_LENGTH, BLANK, OUTPUT_LENGTH, right,
  283.         SIDE_LENGTH, BLANK, V_LINE);
  284.   }
  285. }
  286.  
  287. void EjectPage(void)
  288. {
  289.   fprintf(prt, "%c", FORM_FEED);
  290. }
  291.  
  292. void ExitProgram(void)
  293. {
  294.   ResetPrinter();
  295.   puts("Good Bye!");
  296.   Cleanup(SYS_NORMAL_CODE);
  297. }
  298.  
  299. void FlushBuffers(void)
  300. {
  301.  
  302. /**
  303.  | In the 2-pages mode, prints the current page as
  304.  | it is (non filled lines will be left blank).
  305. **/
  306.  
  307.   int i;
  308.  
  309.   switch (PageMode) {
  310.     case LEFT_PAGE:
  311.       if (!ThisLine) return;
  312.       for (i=0; i<ThisLine; i++) {
  313.         DoubleLine(pPB->line[i], NULL);
  314.         InterLine();
  315.       }
  316.       for (i=ThisLine; i<PAGE_LENGTH; i++) {
  317.         DoubleLine(NULL, NULL);
  318.         InterLine();
  319.       }
  320.       Header(DOWN);
  321.       break;
  322.     case RIGHT_PAGE:
  323.       for (i=ThisLine; i<PAGE_LENGTH; i++) {
  324.         DoubleLine(pPB->line[i], NULL);
  325.         InterLine();
  326.       }
  327.       Header(DOWN);
  328.       break;
  329.   }
  330. }
  331.  
  332. void Header(
  333.   int type
  334. ){
  335.  
  336. /**
  337.  | Prints the top or the down header in the 2-pages mode:
  338.  | a solid line separated from the text by a blank line.
  339. **/
  340.  
  341.   memset(Buffer, H_LINE, TOTAL_LENGTH);
  342.  
  343.   if (type == UP) {
  344.     fprintf(prt, "%c%.*s%c%*c%c%.*s%c\r",
  345.          NW, TOTAL_LENGTH, Buffer, NE, SEP_LENGTH,
  346.          BLANK, NW, TOTAL_LENGTH, Buffer, NE);
  347.     InterLine();
  348.   }
  349.   DoubleLine(NULL, NULL);
  350.   InterLine();
  351.   if (type == DOWN) {
  352.     fprintf(prt, "%c%.*s%c%*c%c%.*s%c\r",
  353.          SW, TOTAL_LENGTH, Buffer, SE, SEP_LENGTH,
  354.          BLANK, SW, TOTAL_LENGTH, Buffer, SE);
  355.     EjectPage();
  356.   }
  357. }
  358.  
  359. void InitPrinter(void)
  360. {
  361.  
  362. /**
  363.  | Printer initialisation: see the HP DeskJet 500
  364.  | user's manual for explanation...
  365. **/
  366.  
  367.   char *PitchID[] = {"10", "12", "16.67", "20", "24"};
  368.  
  369.   if ((prt = fopen(OUTPUT_DEVICE, "w")) == NULL) {
  370.     printf("Can't access the output port ...\n");
  371.     Cleanup(SYS_ABORT_CODE);
  372.   }
  373.   fprintf(prt, "%c&l%do%dD%c(10U%c(s0u", ESC, Orientation, Lpi, ESC, ESC);
  374.   if (Pitch == PROPORTIONAL) {
  375.     fprintf(prt, "1p");
  376.   } else {
  377.     fprintf(prt, "0p%sh", PitchID[Pitch]);
  378.   }
  379.   fprintf(prt, "%dv%ds0b%dt%dQ", Height, Style, Font, Quality);
  380. }
  381.  
  382. void InterLine(void)
  383. {
  384.  
  385. /**
  386.  | Writing at 8 lines per inch and 6 points high characters,
  387.  | the double page border is not continuous. This procedure
  388.  | skips half line, draws the border, then skips another half
  389.  | line down to the correct placement for next printing.
  390. **/
  391.  
  392.   fprintf(prt, "%c=", ESC);
  393.   DoubleLine(NULL, NULL);
  394.   fprintf(prt, "%c=", ESC);
  395. }
  396.  
  397. void OutLine(void)
  398. {
  399.  
  400. /**
  401.  | Outputs a line to the printer.
  402.  | In the normal mode, the line is sent to the port after storing a
  403.  | carriage return and a line feed after the text, and leaving to the
  404.  | printer to deal with form feeds and long lines.
  405.  | In the 2-pages mode, the line is truncated to a fixed length: if
  406.  | we are in the left page, the line is stored in the internal buffer;
  407.  | otherwise, it is printed together with the corresponding left line.
  408. **/
  409.  
  410.   int length, n;
  411.   static char *EndOfLine = "\r\n";
  412.  
  413.   length = strlen(inBuffer) - 1;
  414.  
  415.   switch (PageMode) {
  416.     case SINGLE_PAGE:
  417.       memcpy(inBuffer+length, EndOfLine, 3);
  418.       fputs(inBuffer, prt);
  419.       break;
  420.     case LEFT_PAGE:
  421.       if (length > OUTPUT_LENGTH) {
  422.         length = OUTPUT_LENGTH;
  423.       }
  424.       memcpy(pPB->line[ThisLine], Buffer, length);
  425.       if (++ThisLine >= PAGE_LENGTH) {
  426.         Header(UP);
  427.         PageMode = RIGHT_PAGE;
  428.         ThisLine = 0;
  429.       }
  430.       break;
  431.     case RIGHT_PAGE:
  432.       if ((n = OUTPUT_LENGTH - length) > 0) {
  433.         memset(Buffer+length, BLANK, n);
  434.       }
  435.       DoubleLine(pPB->line[ThisLine], Buffer);
  436.       InterLine();
  437.       if (++ThisLine >= PAGE_LENGTH) {
  438.         Header(DOWN);
  439.         PageMode = LEFT_PAGE;
  440.         ClearPageBuffer();
  441.       }
  442.       break;
  443.   }
  444. }
  445.  
  446. void ResetPrinter(void)
  447. {
  448.   fprintf(prt, "%cE", ESC);
  449. }
  450.  
  451. char **Setup(
  452.   int *pArgc,
  453.   char **argv
  454. ){
  455.  
  456. /**
  457.  | We look into the command line for switches; the function value is
  458.  | argv when pointing to the first non-switch argument (i.e. the first
  459.  | file name) - if any. If the 2-page mode was requested, the procedure
  460.  | allocates from the heap memory the internal buffer for the left-page
  461.  | lines, and a service buffer filled with the pointers to the first
  462.  | character of every line in the left page; this calling malloc(),
  463.  | to make this program more portable.
  464. **/
  465.  
  466.   int i;
  467.   char c;
  468.  
  469.   printf("\n\t\"PF\" - v%.2f - MLO %ld\n\n", VERSION, LAST_CHANGE);
  470.  
  471. /**
  472.  | Error if called from the Workbench, or if called
  473.  | from the CLI but without any argument.
  474. **/
  475.  
  476.   if (*pArgc == 0) {
  477.     printf("This program must be called from CLI;\n"
  478.            "type PF for a short help screen.\n\n"
  479.            "Press <CR> to exit ... ");
  480.     while ((i = getchar()) != NEWLINE && i != EOF)  { }
  481.     Cleanup(SYS_ABORT_CODE);
  482.   }
  483.   if (*pArgc < 2) Syntax();
  484.  
  485.   while (--(*pArgc)) {
  486.     if ((*++argv)[0] == '-') {
  487.  
  488. /**
  489.  | A switch ...
  490. **/
  491.  
  492.       for (i=1; (c = (*argv)[i]); i++) {
  493.         switch (c) {
  494.           case 'l': case 'L':
  495.             Orientation = LANDSCAPE;
  496.             break;
  497.           case 'i': case 'I':
  498.             Style = ITALIC;
  499.             break;
  500.           case 'b': case 'B':
  501.             nBlanks = atoi(*argv + ++i);
  502.             goto NextSwitch;
  503.           case 'a': case 'A':
  504.             nTabs = atoi(*argv + ++i);
  505.             goto NextSwitch;
  506.           case 'g': case 'G':
  507.             Font = GOTHIC;
  508.             break;
  509.           case 't': case 'T':
  510.             Font = TIMES;
  511.             break;
  512.           case 's': case 'S':
  513.             Pitch = P16_67CPI;
  514.             break;
  515.           case 'x': case 'X':
  516.             Pitch = P20CPI;
  517.             break;
  518.           case '6':
  519.             Height = 6;
  520.             break;
  521.           case '8':
  522.             Lpi = 8;
  523.             break;
  524.           case 'd': case 'D':
  525.             Quality = DRAFT;
  526.             break;
  527.           case '2':
  528.             PageMode = LEFT_PAGE;
  529.             break;
  530.           default:
  531.             Syntax();
  532.         }
  533.       }
  534.     } else {
  535.  
  536. /**
  537.  | The first file name; perform some
  538.  | intialisations, then return to the caller.
  539. **/
  540.  
  541.       if (PageMode != SINGLE_PAGE) {
  542.         if ((pPB = malloc(sizeof(PageBuffer))) == NULL) {
  543.           printf("Can't allocate the Page Buffer ...\n");
  544.           Cleanup(SYS_ABORT_CODE);
  545.         }
  546.         if ((pPB->line[0] = malloc(BUFFER_SIZE)) == NULL) {
  547.           printf("Can't allocate the Line Buffer ...\n");
  548.           Cleanup(SYS_ABORT_CODE);
  549.         }
  550.         for (i=1; i<PAGE_LENGTH; i++) {
  551.           pPB->line[i] = pPB->line[0] + (i * OUTPUT_LENGTH);
  552.         }
  553.  
  554.         Orientation = LANDSCAPE;
  555.         Font = COURIER;
  556.         Style = ROMAN;
  557.         Pitch = P16_67CPI;
  558.         Height = 6;
  559.         Lpi = 8;
  560.         nBlanks = 0;
  561.         ClearPageBuffer();
  562.       } else {
  563.         CheckDefaults();
  564.       }
  565.       return argv;
  566.     }
  567.  
  568. NextSwitch: ;
  569.   }
  570.  
  571. /**
  572.  | Here if no file name given; initialise
  573.  | the printer, then exit without reset.
  574. **/
  575.  
  576.   CheckDefaults();
  577.   InitPrinter();
  578.   puts("Printer initialised ... Good bye!");
  579.   Cleanup(SYS_NORMAL_CODE);
  580. }
  581.  
  582. void Syntax(void)
  583. {
  584.  
  585. /**
  586.  | A syntax error has been detected in the command
  587.  | line; a short help is output to the screen.
  588. **/
  589.  
  590.   puts("Usage:    PF   [switches]   [file [file [file ... ] ] ]");
  591.   puts("Switches: -l : Landscape (default is Portrait);");
  592.   puts("          -i : Italic (default is Roman);");
  593.   puts("         -bN : insert N Blanks before every output line;");
  594.   puts("         -aN : tAb stops every N characters (default: 8);");
  595.   puts("          -g : Letter-Gothic font (default is Courier);");
  596.   puts("          -t : Times font (default is Courier);");
  597.   puts("          -s : Small pitch (Courier: 16.67 cpi; "
  598.        "Letter-Gothic: 24 cpi);");
  599.   puts("          -x : eXtra-small pitch (20 cpi - for Courier only);");
  600.   puts("          -8 : 8 lines per inch (default: 6 lpi);");
  601.   puts("          -6 : 6 points high font (default: 12 points);");
  602.   puts("          -d : Draft quality (default is Letter quality);");
  603.   puts("          -2 : special mode (2 pages on every sheet of paper).\n");
  604.   puts("The s/x/l switches are ignored when incompatible with selected font.");
  605.   puts("The default pitch is 10 cpi for Courier and 12 cpi for Letter-Gothic");
  606.   puts("(Times is a proportional font);  all switches different  from -d and");
  607.   puts("-a will be ignored,  if -2 is selected.  The switches on the command");
  608.   puts("line can be grouped: e.g. -c -8 -s is the same as -c8s; only -bN and");
  609.   puts("-aN, if present, must be specified alone or the last in a group. The");
  610.   puts("printer is reset to its default,  at the completion  -  UNLESS if no");
  611.   puts("file names are given.\n");
  612.  
  613.   Cleanup(SYS_NORMAL_CODE);
  614. }
  615.